package org.example.classtopia.Service.Impl;

import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.edge.EdgeOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * Selenium服务类，用于处理Web自动化任务。
 * <p>
 * 该服务采用“按需创建，用完即毁”的模式。
 * 每个公开方法都会在内部创建一个独立的WebDriver实例，并在操作完成后（无论成功或失败）确保其被关闭。
 * 这种模式确保了：
 * 1. 线程安全和数据隔离：每个用户的请求都在一个独立的浏览器会话中处理，杜绝了数据混淆的风险。
 * 2. 资源管理：防止了僵尸浏览器进程的产生，用完即释放资源，保证了服务器的稳定性。
 * </p>
 */
@Service
public class SeleniumService {

    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    /**
     * 创建并配置一个新的、独立的WebDriver实例。
     * 这个方法是私有的，因为它只应该在此服务内部被调用，作为每个任务的起始步骤。
     *
     * @return 配置好的 WebDriver 实例
     */
    private WebDriver createDriver() {
        // 使用WebDriverManager自动管理浏览器驱动
        WebDriverManager.edgedriver().setup();

        EdgeOptions options = new EdgeOptions();

        // --- 核心配置 ---
        // 使用无头模式（Headless Mode），在服务器上运行时无需图形界面，节约资源。
        //options.addArguments("--headless");
        // 禁用GPU加速，这在无头模式下是推荐的，可以避免一些渲染问题。
        options.addArguments("--disable-gpu");
        // 解决在某些Linux服务器环境下可能出现的权限问题。
        options.addArguments("--no-sandbox");
        // 解决某些Docker容器环境下/dev/shm空间不足的问题。
        options.addArguments("--disable-dev-shm-usage");

        // --- 反爬虫策略 ---
        // 移除"正受到自动测试软件的控制"的提示条
        options.setExperimentalOption("excludeSwitches", Collections.singletonList("enable-automation"));
        // 禁用自动化相关的扩展
        options.setExperimentalOption("useAutomationExtension", false);
        // 禁用Blink运行时的某些自动化特征
        options.addArguments("--disable-blink-features=AutomationControlled");
        // 设置一个常规的User-Agent，使其看起来像一个普通的浏览器
        options.addArguments("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0");

        EdgeDriver driver = new EdgeDriver(options);

        // 在页面加载任何脚本之前，执行JavaScript来修改navigator.webdriver属性，这是常见的反爬检测点。
        driver.executeCdpCommand("Page.addScriptToEvaluateOnNewDocument", new HashMap<>() {{
            put("source", "Object.defineProperty(navigator, 'webdriver', { get: () => undefined });");
        }});

        return driver;
    }

    private List<String> calculateCrawlDates(String startDateStr){
        List<String> dates = new ArrayList<>();

        try{
            //解析开始日期
            LocalDate startDate = LocalDate.parse(startDateStr, DATE_FORMATTER);
            LocalDate currentDate = startDate;
            LocalDate endDate = startDate.plusWeeks(4);

            while(currentDate.isBefore(endDate)){
                dates.add(currentDate.format(DATE_FORMATTER));
                currentDate = currentDate.plusWeeks(1);
            }
        }
        catch (Exception e){
            System.err.println("日期解析错误！" + e.getMessage());
            dates.add(startDateStr);
        }
        return dates;
    }

    private String getCurriculumByDate(WebDriver driver, String date){
        try{
            driver.get("https://zhlj.whu.edu.cn/whdxIndex/getCurriculum?date=" + date);

            Thread.sleep(1000);
            String pageSource = driver.getPageSource();
            if(pageSource.contains("<pre>")){
                return driver.findElement(By.tagName("pre")).getText();
            }
            return pageSource;
        }
        catch (Exception e){
            return "获取日期" + date + "的课程信息出错" + e.getMessage();
        }
    }
    /**
     * 一个完整的业务流程：为单个用户请求处理登录并获取课程信息。
     * 此方法是线程安全的，因为所有操作都在一个临时的、独立的WebDriver实例中完成。
     *
     * @param username 用户的登录名
     * @param password 用户的密码
     * @param date     需要查询的课程日期
     * @return 包含课程信息的JSON字符串，或者在发生错误时返回错误信息。
     */
    public Map<String, String> loginAndGetCurriculum(String username, String password, String date) {
        // 关键：WebDriver实例是一个局部变量，生命周期仅限于本次方法调用。
        WebDriver driver = null;
        Map<String, String> result = new HashMap<>();

        try {
            // 步骤1: 为本次请求创建独立的WebDriver实例。
            // 如果此时有另一个请求进来，它也会创建一个属于它自己的实例，两者互不干扰。
            driver = createDriver();

            // 步骤2: 在这个独立的浏览器实例中执行所有自动化操作。
            driver.get("https://cas.whu.edu.cn/authserver/login?service=https%3A%2F%2Fzhlj.whu.edu.cn%2FcasLogin");

            // 设置显式等待，等待元素出现，增加脚本的稳定性。
            WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));

            // --- 登录逻辑 ---
            wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("/html/body/div/div[2]/div[3]/div[2]/div[5]/div[2]/form/div[1]/input")))
                    .sendKeys(username);
            driver.findElement(By.xpath("/html/body/div/div[2]/div[3]/div[2]/div[5]/div[2]/form/div[2]/input[1]")).sendKeys(password);
            driver.findElement(By.xpath("/html/body/div/div[2]/div[3]/div[2]/div[5]/div[2]/form/p[2]/button")).click();

            // 等待登录成功并跳转到目标页面
            wait.until(ExpectedConditions.urlContains("zhlj.whu.edu.cn/pc/index"));

            List<String> crawlDates = calculateCrawlDates(date);

            System.out.println("准备爬取以下日期周次的课程信息" + crawlDates);

            for(String crawlDate : crawlDates){
                String curriculumData = getCurriculumByDate(driver, crawlDate);
                result.put(crawlDate, curriculumData);

                Thread.sleep(3000);//避免频繁请求
            }


        } catch (Exception e) {
            // 捕获所有可能的异常（如超时、元素找不到等），打印日志并返回错误信息。
            e.printStackTrace();

        } finally {
            // 步骤3: 无论成功与否，必须在finally块中关闭WebDriver，释放所有资源。
            // 这是保证服务器不会因进程堆积而崩溃的核心。
            if (driver != null) {
                driver.quit(); // quit()会关闭所有关联的窗口和标签，并安全地终止浏览器驱动进程。
            }
        }

        return result;
    }

    public String getCurriculum(String date) {
        try {
            WebDriver driver = createDriver();
            // 确保已登录
            if (!driver.getCurrentUrl().contains("zhlj.whu.edu.cn")) {
                return "请先登录";
            }

            // 访问课程API
            driver.get("https://zhlj.whu.edu.cn/whdxIndex/getCurriculum?date=" + date);

            // 获取页面源码
            String pageSource = driver.getPageSource();

            // 如果API返回JSON在<pre>标签中
            if (pageSource.contains("<pre>")) {
                return pageSource.substring(pageSource.indexOf("<pre>") + 5, pageSource.indexOf("</pre>"));
            }

            return pageSource;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
